﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EvoAlgLib
{
    public class GPIndividual: Individual
    {
        private static double[,] _data = new double[192,3] {
        {0.00000,0.50000,1.0},
        {-0.00000,-0.50000,0.0},
{-0.10974,0.55169,1.0},{0.10974,-0.55169,0.0},
{-0.23918,0.57742,1.0},
{0.23918,-0.57742,0.0},
{-0.38195,0.57164,1.0},
{0.38195,-0.57164,0.0},
{-0.53033,0.53033,1.0},
{0.53033,-0.53033,0.0},
{-0.67557,0.45140,1.0},
{0.67557,-0.45140,0.0},
{-0.80839,0.33485,1.0},
{0.80839,-0.33485,0.0},
{-0.91949,0.18290,1.0},
{0.91949,-0.18290,0.0},
{-1.00000,-0.00000,1.0},
{1.00000,0.00000,0.0},
{-1.04208,-0.20728,1.0},
{1.04208,0.20728,0.0},
{-1.03936,-0.43052,1.0},
{1.03936,0.43052,0.0},
{-0.98737,-0.65974,1.0},
{0.98737,0.65974,0.0},
{-0.88388,-0.88388,1.0},
{0.88388,0.88388,0.0},
{-0.72919,-1.09130,1.0},
{0.72919,1.09130,0.0},
{-0.52619,-1.27033,1.0},
{0.52619,1.27033,0.0},
{-0.28044,-1.40988,1.0},
{0.28044,1.40988,0.0},
{0.00000,-1.50000,1.0},
{-0.00000,1.50000,0.0},
{0.30483,-1.53248,1.0},
{-0.30483,1.53248,0.0},
{0.62186,-1.50130,1.0},
{-0.62186,1.50130,0.0},
{0.93752,-1.40310,1.0},
{-0.93752,1.40310,0.0},
{1.23744,-1.23744,1.0},
{-1.23744,1.23744,0.0},
{1.50704,-1.00697,1.0},
{-1.50704,1.00697,0.0},
{1.73227,-0.71753,1.0},
{-1.73227,0.71753,0.0},
{1.90027,-0.37799,1.0},
{-1.90027,0.37799,0.0},
{2.00000,-0.00000,1.0},
{-2.00000,0.00000,0.0},
{2.02287,0.40237,1.0},
{-2.02287,-0.40237,0.0},
{1.96324,0.81320,1.0},
{-1.96324,-0.81320,0.0},
{1.81884,1.21531,1.0},
{-1.81884,-1.21531,0.0},
{1.59099,1.59099,1.0},
{-1.59099,-1.59099,0.0},
{1.28476,1.92277,1.0},
{-1.28476,-1.92277,0.0},
{0.90887,2.19421,1.0},
{-0.90887,-2.19421,0.0},
{0.47553,2.39066,1.0},
{-0.47553,-2.39066,0.0},
{0.00000,2.50000,1.0},
{-0.00000,-2.50000,0.0},
{-0.49992,2.51326,1.0},
{0.49992,-2.51326,0.0},
{-1.00454,2.42518,1.0},
{1.00454,-2.42518,0.0},
{-1.49310,2.23457,1.0},
{1.49310,-2.23457,0.0},
{-1.94454,1.94454,1.0},
{1.94454,-1.94454,0.0},
{-2.33851,1.56254,1.0},
{2.33851,-1.56254,0.0},
{-2.65615,1.10021,1.0},
{2.65615,-1.10021,0.0},
{-2.88106,0.57308,1.0},
{2.88106,-0.57308,0.0},
{-3.00000,-0.00000,1.0},
{3.00000,0.00000,0.0},
{-3.00365,-0.59746,1.0},
{3.00365,0.59746,0.0},
{-2.88712,-1.19589,1.0},
{2.88712,1.19589,0.0},
{-2.65031,-1.77088,1.0},
{2.65031,1.77088,0.0},
{-2.29810,-2.29810,1.0},
{2.29810,2.29810,0.0},
{-1.84033,-2.75424,1.0},
{1.84033,2.75424,0.0},
{-1.29156,-3.11809,1.0},
{1.29156,3.11809,0.0},
{-0.67062,-3.37145,1.0},
{0.67062,3.37145,0.0},
{-0.00000,-3.50000,1.0},
{0.00000,3.50000,0.0},
{0.69501,-3.49405,1.0},
{-0.69501,3.49405,0.0},
{1.38723,-3.34906,1.0},
{-1.38723,3.34906,0.0},
{2.04866,-3.06604,1.0},
{-2.04866,3.06604,0.0},
{2.65165,-2.65165,1.0},
{-2.65165,2.65165,0.0},
{3.16998,-2.11811,1.0},
{-3.16998,2.11811,0.0},
{3.58003,-1.48290,1.0},
{-3.58003,1.48290,0.0},
{3.86184,-0.76817,1.0},
{-3.86184,0.76817,0.0},
{4.00000,0.00000,1.0},
{-4.00000,-0.00000,0.0},
{3.98444,0.79256,1.0},
{-3.98444,-0.79256,0.0},
{3.81100,1.57857,1.0},
{-3.81100,-1.57857,0.0},
{3.48178,2.32645,1.0},
{-3.48178,-2.32645,0.0},
{3.00520,3.00520,1.0},
{-3.00520,-3.00520,0.0},
{2.39590,3.58571,1.0},
{-2.39590,-3.58571,0.0},
{1.67424,4.04197,1.0},
{-1.67424,-4.04197,0.0},
{0.86571,4.35223,1.0},
{-0.86571,-4.35223,0.0},
{0.00000,4.50000,1.0},
{-0.00000,-4.50000,0.0},
{-0.89010,4.47483,1.0},
{0.89010,-4.47483,0.0},
{-1.76991,4.27294,1.0},
{1.76991,-4.27294,0.0},
{-2.60424,3.89751,1.0},
{2.60424,-3.89751,0.0},
{-3.35876,3.35876,1.0},
{3.35876,-3.35876,0.0},
{-4.00145,2.67368,1.0},
{4.00145,-2.67368,0.0},
{-4.50391,1.86558,1.0},
{4.50391,-1.86558,0.0},
{-4.84263,0.96326,1.0},
{4.84263,-0.96326,0.0},
{-5.00000,0.00000,1.0},
{5.00000,-0.00000,0.0},
{-4.96523,-0.98765,1.0},
{4.96523,0.98765,0.0},
{-4.73488,-1.96125,1.0},
{4.73488,1.96125,0.0},
{-4.31325,-2.88202,1.0},
{4.31325,2.88202,0.0},
{-3.71231,-3.71231,1.0},
{3.71231,3.71231,0.0},
{-2.95147,-4.41718,1.0},
{2.95147,4.41718,0.0},
{-2.05692,-4.96585,1.0},
{2.05692,4.96585,0.0},
{-1.06080,-5.33302,1.0},
{1.06080,5.33302,0.0},
{-0.00000,-5.50000,1.0},
{0.00000,5.50000,0.0},
{1.08519,-5.45562,1.0},
{-1.08519,5.45562,0.0},
{2.15259,-5.19682,1.0},
{-2.15259,5.19682,0.0},
{3.15981,-4.72898,1.0},
{-3.15981,4.72898,0.0},
{4.06586,-4.06586,1.0},
{-4.06586,4.06586,0.0},
{4.83292,-3.22925,1.0},
{-4.83292,3.22925,0.0},
{5.42779,-2.24827,1.0},
{-5.42779,2.24827,0.0},
{5.82341,-1.15835,1.0},
{-5.82341,1.15835,0.0},
{6.00000,-0.00000,1.0},
{-6.00000,0.00000,0.0},
{5.94601,1.18274,1.0},
{-5.94601,-1.18274,0.0},
{5.65876,2.34394,1.0},
{-5.65876,-2.34394,0.0},
{5.14472,3.43759,1.0},
{-5.14472,-3.43759,0.0},
{4.41942,4.41942,1.0},
{-4.41942,-4.41942,0.0},
{3.50704,5.24865,1.0},
{-3.50704,-5.24865,0.0},
{2.43961,5.88973,1.0},
{-2.43961,-5.88973,0.0},
{1.25589,6.31381,1.0},
{-1.25589,-6.31381,0.0}};

        private Node _genotype;
        private int _age;
        private bool _dirty;
        private double _fitness;
        private double p_m;

        public GPIndividual(Node root, double pm)
        {
            this._genotype = root;
            this._age = 0;
            this._dirty = true;
            this.p_m = pm;
        }

        public GPIndividual(GPIndividual other)
        {
            this._genotype = new Node(other._genotype);
            this._age = other._age;
            this._fitness = other._fitness;
            this._dirty = other._dirty;
            this.p_m = other.p_m;
        }

        public void dirty()
        {
            this._dirty = true;
        }

        public List<int> getResults()
        {
            List<int> resList = new List<int>();
            for (int i = 0; i < GPIndividual._data.GetLength(0); i++)
            {
                Dictionary<String, double> vars = new Dictionary<string, double>();
                vars["x"] = GPIndividual._data[i, 0];
                vars["y"] = GPIndividual._data[i, 1];
                try
                {
                    double res = this._genotype.execute(vars);
                    if (Double.IsInfinity(res) || Double.IsNaN(res))
                    {
                        resList.Add(0);
                        continue;
                    }
                    if (res > 0)
                        resList.Add(1);
                    else if (res < 0)
                        resList.Add(-1);
                    else
                        resList.Add(0);
                }
                catch (DivideByZeroException)
                {
                    resList.Add(0);
                }

            }
            return resList;
        }

        public double getFitness()
        {
            if (this._dirty)
            {
                this._fitness = 0;
                for (int i = 0; i < GPIndividual._data.GetLength(0); i++)
                {
                    Dictionary<String, double> vars = new Dictionary<string, double>();
                    vars["x"] = GPIndividual._data[i,0];
                    vars["y"] = GPIndividual._data[i,1];
                    try
                    {
                        double res = this._genotype.execute(vars);
                        if (Double.IsInfinity(res) || Double.IsNaN(res))
                        {
                            continue;
                        }
                        if (res > 0 && GPIndividual._data[i, 2] > 0)
                            this._fitness++;
                        if (res < 0 && GPIndividual._data[i, 2] <= 0)
                            this._fitness++;
                    } catch (DivideByZeroException)
                        {
                            continue;
                        }
                
                }
                this._dirty = false;
            }
            return this._fitness;
        }

        public String plotDisplay()
        {
            return this._genotype.ToString();
        }

        public Individual mutate()
        {
            _genotype.mutate(p_m);
            return this;
        }

        public object getGenotype()
        {
            return this._genotype;
        }

        public void setGenotype(Node n)
        {
            this._genotype = n;
        }

        public int getAge()
        {
            return this._age;
        }
        public void incAge()
        {
            this._age++;
        }

        public override String ToString()
        {
            return this._genotype.ToString();
        }

        int IComparable.CompareTo(object obj)
        {
            GPIndividual other = (GPIndividual)obj;
            double t = this.getFitness();
            double o = other.getFitness();
            if (t > o)
                return 1;
            if (t < o)
                return -1;
            return 0;
        }
    }
}
